package com.wushijia.io;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;

/**
 * description:启动服务，浏览器访问http://localhost:8080/，在浏览器不显示信息?
 *
 * @author yang
 * @date 2018/1/7 18:21
 */
public class NioServer {

  public static void main(String[] args) throws Exception {
    ServerSocketChannel ssc = ServerSocketChannel.open();
    ssc.socket().bind(new InetSocketAddress(8080));
    //设置为非阻塞模式
    ssc.configureBlocking(false);

    Selector selector = Selector.open();
    ssc.register(selector, SelectionKey.OP_ACCEPT);

    while (true) {
      if (selector.select(3000) == 0) {
        System.out.println("等待请求超时");
        continue;
      }

      System.out.println("处理请求。。。");
      Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
      while (iterator.hasNext()) {
        SelectionKey key = iterator.next();
        new Thread(new Handler(key)).run();
        iterator.remove();
      }
    }
  }

  private static class Handler implements Runnable {

    //报文长度
    private int bufferSize = 1024;
    private String localCharset = "UTF-8";
    private SelectionKey key;

    public Handler(SelectionKey key) {
      this.key = key;
    }

    public Handler(int bufferSize) {
      this(bufferSize, null);
    }

    public Handler(String localCharset) {
      this(-1, localCharset);
    }

    public Handler(int bufferSize, String localCharset) {
      if (bufferSize > 0) {
        this.bufferSize = bufferSize;
      }
      if (localCharset != null) {
        this.localCharset = localCharset;
      }
    }

    private void handlerAccept() throws IOException {
      SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
      sc.configureBlocking(false);
      sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
    }

    private void handleRead() throws IOException {
      SocketChannel sc = (SocketChannel) key.channel();
      ByteBuffer buffer = (ByteBuffer) key.attachment();
      buffer.clear();
      if (sc.read(buffer) == -1) {
        sc.close();
      } else {
        //将buffer转换为读状态
        buffer.flip();
        String receivedString = Charset.forName(localCharset).newDecoder().decode(buffer).toString();
        System.out.println("received from client:" + receivedString);

        String sendString = "received data:" + receivedString;
        buffer = ByteBuffer.wrap(sendString.getBytes(localCharset));
        sc.write(buffer);
        sc.close();
      }
    }

    @Override
    public void run() {
      try {
        if (key.isAcceptable()) {
          handlerAccept();
        }
        if (key.isReadable()) {
          handleRead();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }

    }
  }
}
